using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using LDNS.Models;
using NLog;

namespace LDNS.Utilities
{
    /// <summary>
    /// 控制台辅助类，提供控制台窗口的显示和隐藏功能
    /// 作者：huobing
    /// </summary>
    public static class DnsDataUtils
    {
        // 日志记录器
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        
        /// <summary>
        /// 测试DNS服务器连接
        /// </summary>
        /// <param name="dnsServer">DNS服务器地址</param>
        /// <param name="timeout">超时时间（毫秒）</param>
        /// <returns>测试结果</returns>
        public static async Task<DnsTestResult> TestDnsServerAsync(string dnsServer, int timeout = 5000)
        {
            var result = new DnsTestResult(false);

            try
            {
                var stopwatch = Stopwatch.StartNew();

                using var ping = new Ping();
                var reply = await ping.SendPingAsync(dnsServer, timeout);

                stopwatch.Stop();

                result.ResponseTimeMs = stopwatch.ElapsedMilliseconds;
                result.IsSuccess = reply.Status == IPStatus.Success;

                if (!result.IsSuccess)
                {
                    result.ErrorMessage = $"Ping失败: {reply.Status}";
                }

                _logger.Info($"测试DNS服务器 {dnsServer}: {(result.IsSuccess ? "成功" : "失败")}，响应时间: {result.ResponseTimeMs}ms");
            }
            catch (Exception ex)
            {
                result.ErrorMessage = ex.Message;
                _logger.Error(ex, $"测试DNS服务器 {dnsServer} 失败: {ex.Message}");
            }

            return result;
        }

        /// <summary>
        /// 创建反向DNS响应（PTR记录）
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <param name="hostname">主机名</param>
        /// <returns>响应数据</returns>
        public static byte[] CreateReverseDnsResponse(byte[] requestData, string hostname)
        {
            try
            {
                // 创建响应列表
                var response = new List<byte>();
                
                // 复制请求头部（事务ID）
                response.AddRange(requestData[0..2]);
                
                // 设置响应标志（设置AA=1表示权威应答）
                response.Add(0x85); // QR=1, OPCODE=0, AA=1, TC=0, RD=1
                response.Add(0x80); // RA=1, Z=0, RCODE=0
                
                // 问题数量（从请求中复制）
                response.AddRange(requestData[4..6]);
                
                // 回答数量 = 1
                response.Add(0x00);
                response.Add(0x01);
                
                // 权威记录数量 = 0
                response.Add(0x00);
                response.Add(0x00);
                
                // 附加记录数量 = 0
                response.Add(0x00);
                response.Add(0x00);
                
                // 复制问题部分（域名查询部分）
                int questionStart = 12;
                int questionEnd = questionStart;
                
                // 找到问题部分的结束位置
                while (questionEnd < requestData.Length && requestData[questionEnd] != 0)
                {
                    int length = requestData[questionEnd];
                    questionEnd += length + 1;
                }
                questionEnd += 5; // 包括结束的0和QType、QClass
                
                if (questionEnd <= requestData.Length)
                {
                    response.AddRange(requestData[questionStart..questionEnd]);
                }
                
                // 添加回答记录
                // 指针到问题部分的域名（0xC0 0x0C）
                response.Add(0xC0);
                response.Add(0x0C);
                
                // 类型 PTR记录 = 12
                response.Add(0x00);
                response.Add(0x0C);
                
                // 类 IN = 1
                response.Add(0x00);
                response.Add(0x01);
                
                // TTL = 300秒
                response.Add(0x00);
                response.Add(0x00);
                response.Add(0x01);
                response.Add(0x2C);
                
                // 构建主机名数据
                var hostnameParts = hostname.Split('.');
                var hostnameData = new List<byte>();
                
                foreach (var part in hostnameParts)
                {
                    hostnameData.Add((byte)part.Length);
                    hostnameData.AddRange(Encoding.UTF8.GetBytes(part));
                }
                hostnameData.Add(0x00); // 结束
                
                // 数据长度
                response.Add((byte)(hostnameData.Count >> 8));
                response.Add((byte)hostnameData.Count);
                
                // 主机名数据
                response.AddRange(hostnameData);
                
                return [.. response];
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"创建反向DNS响应失败: {ex.Message}");
                
                // 返回一个基本的错误响应
                var basicResponse = new List<byte>();
                basicResponse.AddRange(requestData[0..2]); // 事务ID
                basicResponse.Add(0x81); // QR=1
                basicResponse.Add(0x83); // RCODE=3（域名不存在）
                basicResponse.AddRange(new byte[10]); // 其他字段设为0
                return [.. basicResponse];
            }
        }

        /// <summary>
        /// 从DNS请求中提取域名
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <returns>域名</returns>
        public static string ExtractDomainFromDnsRequest(byte[] requestData)
        {
            try
            {
                // 简化实现：假设请求格式为标准的DNS查询
                if (requestData.Length < 12) return string.Empty;
                
                var domainParts = new List<string>();
                int position = 12; // 跳过DNS头部
                
                while (position < requestData.Length && requestData[position] != 0)
                {
                    int length = requestData[position];
                    position++;
                    
                    if (position + length > requestData.Length) break;
                    
                    var part = Encoding.UTF8.GetString(requestData, position, length);
                    domainParts.Add(part);
                    position += length;
                }
                
                return string.Join(".", domainParts);
            }
            catch
            {
                return string.Empty;
            }
        }
        
        /// <summary>
        /// 从DNS请求中提取查询类型
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <returns>查询类型的字符串表示</returns>
        public static string ExtractQueryTypeFromDnsRequest(byte[] requestData)
        {
            try
            {
                // 简化实现：假设请求格式为标准的DNS查询
                if (requestData.Length < 14) return string.Empty;
                
                int position = 12; // 跳过DNS头部
                
                // 跳过域名部分
                while (position < requestData.Length && requestData[position] != 0)
                {
                    int length = requestData[position];
                    position++;
                    
                    if (position + length > requestData.Length) return string.Empty;
                    position += length;
                }
                
                // 检查是否有足够的字节来读取查询类型
                if (position + 2 >= requestData.Length) return string.Empty;
                
                // 跳过域名结束符
                position++;
                
                // 读取查询类型（2字节）
                int qtype = (requestData[position] << 8) | requestData[position + 1];
                
                // 返回查询类型的字符串表示
                return GetQueryTypeName(qtype);
            }
            catch
            {
                return string.Empty;
            }
        }
        
        /// <summary>
        /// 根据查询类型值获取查询类型名称
        /// </summary>
        /// <param name="qtype">查询类型值</param>
        /// <returns>查询类型名称</returns>
        private static string GetQueryTypeName(int qtype)
        {
            switch (qtype)
            {
                case 1: return "A";
                case 28: return "AAAA";
                case 5: return "CNAME";
                case 12: return "PTR";
                case 15: return "MX";
                case 16: return "TXT";
                case 2: return "NS";
                case 6: return "SOA";
                case 33: return "SRV";
                default: return qtype.ToString();
            }
        }

        /// <summary>
        /// 创建反向DNS响应（PTR记录）
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <param name="hostname">主机名</param>
        /// <returns>响应数据</returns>
        /// <summary>
        /// 创建DNS响应（支持多个IP地址）
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <param name="ipAddresses">IP地址列表</param>
        /// <returns>响应数据</returns>
        public static byte[] CreateDnsResponse(byte[] requestData, List<string> ipAddresses)
        {
            try
            {
                // 验证IP地址列表
                if (ipAddresses == null || ipAddresses.Count == 0)
                {
                    _logger.Error("IP地址列表为空，无法创建DNS响应");
                    return CreateErrorResponse(requestData, 3); // RCODE=3（域名不存在）
                }

                // 对IP地址进行去重
                var uniqueIpAddresses = ipAddresses.Distinct().ToList();
                
                // 创建响应列表
                var response = new List<byte>();
                
                // 复制请求头部（事务ID）
                response.AddRange(requestData[0..2]);
                
                // 设置响应标志（设置AA=1表示权威应答）
                response.Add(0x85); // QR=1, OPCODE=0, AA=1, TC=0, RD=1
                response.Add(0x80); // RA=1, Z=0, RCODE=0
                
                // 问题数量（从请求中复制）
                response.AddRange(requestData[4..6]);
                
                // 回答数量 = 去重后的IP地址数量
                response.Add((byte)(uniqueIpAddresses.Count >> 8));
                response.Add((byte)uniqueIpAddresses.Count);
                
                // 权威记录数量 = 1（添加SOA记录）
                response.Add(0x00);
                response.Add(0x01);
                
                // 附加记录数量 = 0
                response.Add(0x00);
                response.Add(0x00);
                
                // 复制问题部分（域名查询部分）
                int questionStart = 12;
                int questionEnd = questionStart;
                
                // 找到问题部分的结束位置
                while (questionEnd < requestData.Length && requestData[questionEnd] != 0)
                {
                    int length = requestData[questionEnd];
                    questionEnd += length + 1;
                }
                questionEnd += 5; // 包括结束的0和QType、QClass
                
                if (questionEnd <= requestData.Length)
                {
                    response.AddRange(requestData[questionStart..questionEnd]);
                }
                
                // 添加回答记录（每个去重后的IP地址一个记录）
                foreach (var ipAddress in uniqueIpAddresses)
                {
                    try
                    {
                        // 解析IP地址
                        var ipBytes = IPAddress.Parse(ipAddress).GetAddressBytes();
                        
                        // 指针到问题部分的域名（0xC0 0x0C）
                        response.Add(0xC0);
                        response.Add(0x0C);
                        
                        // 类型 A记录 = 1
                        response.Add(0x00);
                        response.Add(0x01);
                        
                        // 类 IN = 1
                        response.Add(0x00);
                        response.Add(0x01);
                        
                        // TTL = 300秒
                        response.Add(0x00);
                        response.Add(0x00);
                        response.Add(0x01);
                        response.Add(0x2C);
                        
                        // 数据长度 = 4（IPv4地址）
                        response.Add(0x00);
                        response.Add(0x04);
                        
                        // IP地址
                        response.AddRange(ipBytes);
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, $"处理IP地址 {ipAddress} 时出错: {ex.Message}");
                        // 跳过无效的IP地址，继续处理下一个
                    }
                }
                
                // 添加权威记录（SOA记录，显示服务器名dns.local）
                // 指针到问题部分的域名（0xC0 0x0C）
                response.Add(0xC0);
                response.Add(0x0C);
                
                // 类型 SOA记录 = 6
                response.Add(0x00);
                response.Add(0x06);
                
                // 类 IN = 1
                response.Add(0x00);
                response.Add(0x01);
                
                // TTL = 300秒
                response.Add(0x00);
                response.Add(0x00);
                response.Add(0x01);
                response.Add(0x2C);
                
                // 数据长度（计算SOA记录数据长度）
                // SOA记录包含：主DNS服务器名、管理员邮箱、序列号、刷新间隔、重试间隔、过期时间、最小TTL
                var soaData = CreateSoaRecordData("dns.local", "admin.dns.local");
                response.Add((byte)(soaData.Length >> 8));
                response.Add((byte)soaData.Length);
                
                // SOA记录数据
                response.AddRange(soaData);
                
                return [.. response];
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"创建DNS响应失败: {ex.Message}");
                
                // 返回一个基本的错误响应
                return CreateErrorResponse(requestData, 3); // RCODE=3（域名不存在）
            }
        }

        /// <summary>
        /// 创建DNS响应
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <param name="ipAddress">IP地址</param>
        /// <returns>响应数据</returns>
        public static byte[] CreateDnsResponse(byte[] requestData, string ipAddress)
        {
            return CreateDnsResponse(requestData, new List<string> { ipAddress });
        }

        /// <summary>
        /// 创建错误响应
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <param name="rcode">响应代码</param>
        /// <returns>错误响应数据</returns>
        private static byte[] CreateErrorResponse(byte[] requestData, int rcode)
        {
            var basicResponse = new List<byte>();
            basicResponse.AddRange(requestData[0..2]); // 事务ID
            basicResponse.Add(0x81); // QR=1
            basicResponse.Add((byte)(0x80 | rcode)); // RA=1, RCODE
            basicResponse.AddRange(requestData[4..6]); // 问题数量
            basicResponse.Add(0x00); // 回答数量 = 0
            basicResponse.Add(0x00); // 权威记录数量 = 0
            basicResponse.Add(0x00); // 附加记录数量 = 0
            return [.. basicResponse];
        }

        /// <summary>
        /// 创建SOA记录数据
        /// </summary>
        /// <param name="primaryNameServer">主DNS服务器名</param>
        /// <param name="responsiblePerson">负责人邮箱</param>
        /// <returns>SOA记录数据</returns>
        public static byte[] CreateSoaRecordData(string primaryNameServer, string responsiblePerson)
        {
            var soaData = new List<byte>();
            
            // 主DNS服务器名（dns.local）
            var primaryParts = primaryNameServer.Split('.');
            foreach (var part in primaryParts)
            {
                soaData.Add((byte)part.Length);
                soaData.AddRange(Encoding.UTF8.GetBytes(part));
            }
            soaData.Add(0x00); // 结束
            
            // 负责人邮箱（admin.dns.local）
            var personParts = responsiblePerson.Split('.');
            foreach (var part in personParts)
            {
                soaData.Add((byte)part.Length);
                soaData.AddRange(Encoding.UTF8.GetBytes(part));
            }
            soaData.Add(0x00); // 结束
            
            // 序列号 = 1
            soaData.Add(0x00);
            soaData.Add(0x00);
            soaData.Add(0x00);
            soaData.Add(0x01);
            
            // 刷新间隔 = 3600秒（1小时）
            soaData.Add(0x00);
            soaData.Add(0x00);
            soaData.Add(0x0E);
            soaData.Add(0x10);
            
            // 重试间隔 = 600秒（10分钟）
            soaData.Add(0x00);
            soaData.Add(0x00);
            soaData.Add(0x02);
            soaData.Add(0x58);
            
            // 过期时间 = 86400秒（1天）
            soaData.Add(0x00);
            soaData.Add(0x01);
            soaData.Add(0x51);
            soaData.Add(0x80);
            
            // 最小TTL = 300秒
            soaData.Add(0x00);
            soaData.Add(0x00);
            soaData.Add(0x01);
            soaData.Add(0x2C);
            
            return [.. soaData];
        }
    }
}